<?php

namespace SpecialOperations\GameBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * SpecialOperations\GameBundle\Entity\District
 */
class District
{
    const TIME=3600;
    /**
     * @var string $name
     */
    private $name;

    /**
     * @var bigint $terrain
     */
    private $terrain;

    /**
     * @var float $population
     */
    private $population;

    /**
     * @var float $coal
     */
    private $coal;

    /**
     * @var float $metal
     */
    private $metal;

    /**
     * @var float $oil
     */
    private $oil;

    /**
     * @var float $energy
     */
    private $energy;

    /**
     * @var float $morale
     */
    private $morale = 1;

    /**
     * @var bigint $owner
     */
    private $owner;

    /**
     * @var bigint $position
     */
    private $position;

    /**
     * @var datetime $created
     */
    private $created;

    /**
     * @var datetime $updated
     */
    private $updated;

    /**
     * @var bigint $id
     */
    private $id;


    /**
     * Set name
     *
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }
    

    /**
     * Set terrain
     *
     * @param bigint $terrain
     */
    public function setTerrain($terrain)
    {
        $this->terrain = $terrain;
    }

    /**
     * Get terrain
     *
     * @return bigint 
     */
    public function getTerrain()
    {
        if(!$this->terrain){
            $this->terrain=new Terrain();
            $this->terrain->setDistrict($this);
        }
        return $this->terrain;
    }

    /**
     * Set population
     *
     * @param float $population
     */
    public function setPopulation($population)
    {
        $this->population = $population;
    }

    /**
     * Get population
     *
     * @return float 
     */
    public function getPopulation()
    {
        return $this->population;
    }

    /**
     * Set coal
     *
     * @param float $coal
     */
    public function setCoal($coal)
    {
        $this->coal = $coal;
    }

    /**
     * Get coal
     *
     * @return float 
     */
    public function getCoal()
    {
        return $this->coal;
    }

    /**
     * Set metal
     *
     * @param float $metal
     */
    public function setMetal($metal)
    {
        $this->metal = $metal;
    }

    /**
     * Get metal
     *
     * @return float 
     */
    public function getMetal()
    {
        return $this->metal;
    }

    /**
     * Set oil
     *
     * @param float $oil
     */
    public function setOil($oil)
    {
        $this->oil = $oil;
    }

    /**
     * Get oil
     *
     * @return float 
     */
    public function getOil()
    {
        return $this->oil;
    }

    /**
     * Set energy
     *
     * @param float $energy
     */
    public function setEnergy($energy)
    {
        $this->energy = $energy;
    }

    /**
     * Get energy
     *
     * @return float 
     */
    public function getEnergy()
    {
        return $this->energy;
    }   

    /**
     * Set morale
     *
     * @param float $morale
     */
    public function setMorale($morale)
    {
        $this->morale = $morale;
    }

    /**
     * Get morale
     *
     * @return float 
     */
    public function getMorale()
    {
        return $this->morale;
    }

    /**
     * Set owner
     *
     * @param bigint $owner
     */
    public function setOwner($owner)
    {
        $this->owner = $owner;
    }

    /**
     * Get owner
     *
     * @return bigint 
     */
    public function getOwner()
    {
        return $this->owner;
    }

    /**
     * Set position
     *
     * @param bigint $position
     */
    public function setPosition($position)
    {
        $this->position = $position;
    }

    /**
     * Get position
     *
     * @return bigint 
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * Set created
     *
     * @param datetime $created
     */
    public function setCreated($created)
    {
        $this->created = $created;
    }

    /**
     * Get created
     *
     * @return datetime 
     */
    public function getCreated()
    {
        return $this->created;
    }

    /**
     * Set updated
     *
     * @param datetime $updated
     */
    public function setUpdated($updated)
    {
        $this->updated = $updated;
    }

    /**
     * Get updated
     *
     * @return datetime 
     */
    public function getUpdated()
    {
        if(!$this->updated){
            return $this->created;
        }
        return $this->updated;  
    }

    /**
     * Get id
     *
     * @return bigint 
     */
    public function getId()
    {
        return $this->id;
    }
    

    public function __construct()
    {
        $this->buildings = new \Doctrine\Common\Collections\ArrayCollection();
    }
    
    
    public function initializeResources(){
        $this->coal=500;        
        $this->metal=500;
        $this->oil=100;
        $this->coalBonus=rand(50,150)/100;
        $this->metalBonus=rand(50,150)/100;
        $this->oilBonus=rand(50,150)/100;
        $this->energyBonus=rand(50,150)/100;
        $this->population=50;
        $this->name=$this->generateName();
    }
    
    public function __ToString(){
        return $this->name;
    }
    /**
     * @var float $coalBonus
     */
    private $coalBonus;

    /**
     * @var float $metalBonus
     */
    private $metalBonus;

    /**
     * @var float $oilBonus
     */
    private $oilBonus;

    /**
     * @var float $energyBonus
     */
    private $energyBonus;


    /**
     * Set coalBonus
     *
     * @param float $coalBonus
     */
    public function setCoalBonus($coalBonus)
    {
        $this->coalBonus = $coalBonus;
    }

    /**
     * Get coalBonus
     *
     * @return float 
     */
    public function getCoalBonus()
    {
        return $this->coalBonus;
    }

    /**
     * Set metalBonus
     *
     * @param float $metalBonus
     */
    public function setMetalBonus($metalBonus)
    {
        $this->metalBonus = $metalBonus;
    }

    /**
     * Get metalBonus
     *
     * @return float 
     */
    public function getMetalBonus()
    {
        return $this->metalBonus;
    }

    /**
     * Set oilBonus
     *
     * @param float $oilBonus
     */
    public function setOilBonus($oilBonus)
    {
        $this->oilBonus = $oilBonus;
    }

    /**
     * Get oilBonus
     *
     * @return float 
     */
    public function getOilBonus()
    {
        return $this->oilBonus;
    }

    /**
     * Set energyBonus
     *
     * @param float $energyBonus
     */
    public function setEnergyBonus($energyBonus)
    {
        $this->energyBonus = $energyBonus;
    }
    
    public function getPopulationNeed(){
        $ret=0;
        foreach ($this->getBuildings() as $building){
//            $building= new Building();
            $ret+=$building->getPopulationConsumption();
        }
        return $ret;
    }
    
    public function getEnergyNeed(){
        $ret=0;
        foreach ($this->getBuildings() as $building){
//            $building= new Building();
            $ret+=$building->getEnergyConsumption();
        }
        return $ret;
    }


    /**
     * Get worst multiplier to use it when counting metal, coal, 
     * @return float
     */
    public function getWorstMultiplier(){
       if($this->getPopulationNeed()==0 && $this->getEnergyNeed()==0){
           return 1;
           
       }
       elseif($this->getPopulationNeed()!=0 && $this->getEnergyNeed()!=0){
            if($this->getPopulation()/$this->getPopulationNeed()>$this->getEnergy()/$this->getEnergyNeed()){
                return $this->getEnergy()/$this->getEnergyNeed();
            } 
            else{
                return $this->getPopulation()/$this->getPopulationNeed();
            }
       }       
       elseif($this->getPopulationNeed()==0){
           return $this->getEnergy()/$this->getEnergyNeed();
       }
       elseif($this->getEnergyNeed()==0){
           return $this->getPopulation()/$this->getPopulationNeed();
       }
    }
    
    public function getCoalProductionRatio(){
        return $this->getCoalMine()->getCoalProductionRatio()*$this->getCoalBonus();
    }
    
    public function timeToCollectCoal($cost=0){
        $need=$cost-$this->getCoal();
        $time=$need/$this->getCoalProductionRatio();
        return $time;
    }
    
    public function getOilProductionRatio(){
        return $this->getRafinery()->getOilProductionRatio()*$this->getOilBonus();
    }
    
    public function timeToCollectOil($cost=0){
        $need=$cost-$this->getOil();
        $time=$need/$this->getOilProductionRatio();
        return $time;
    }

    public function getMetalProductionRatio(){
        return $this->getMetalworks()->getMetalProductionRatio()*$this->getMetalBonus();
    }
    
    public function timeToCollectMetal($cost=0){
        $need=$cost-$this->getMetal();
        $time=$need/$this->getMetalProductionRatio();
        return $time;
    }

    /**
     * Get energyBonus
     *
     * @return float 
     */
    public function getEnergyBonus()
    {
        return $this->energyBonus;
    }
    
    private function generateName(){
        $letters= 'ABCDEFGHIJKLMNOUPRSTUQWXYZ1234567890';
        $name='';
        for($i=0 ; $i<=4; $i++){           
            $name.=$letters[rand(0,25)];
        }
        for($i=0 ; $i<4; $i++){
            $name.=$letters[rand(26, 35)];
        }
        $name.='-'.$letters[rand(0,25)].$letters[rand(26, 35)].$letters[rand(26, 35)];
        return $name;
    }
    /**
     * @var SpecialOperations\GameBundle\Entity\CoalMine
     */
    private $coalMine;


    /**
     * Set coalMine
     *
     * @param SpecialOperations\GameBundle\Entity\CoalMine $coalMine
     */
    public function setCoalMine(\SpecialOperations\GameBundle\Entity\CoalMine $coalMine)
    {
        $this->coalMine = $coalMine;
    }

    /**
     * Get coalMine
     *
     * @return SpecialOperations\GameBundle\Entity\CoalMine 
     */
    public function getCoalMine()
    {
        if(!$this->coalMine){
            $this->coalMine=new CoalMine();
            $this->coalMine->setDistrict($this);            
        }
        return $this->coalMine;
    }
    /**
     * @var SpecialOperations\GameBundle\Entity\Metalworks
     */
    private $metalworks;

    /**
     * @var SpecialOperations\GameBundle\Entity\Rafinery
     */
    private $rafinery;

    /**
     * @var SpecialOperations\GameBundle\Entity\PowerPlant
     */
    private $powerPlant;


    /**
     * Set metalworks
     *
     * @param SpecialOperations\GameBundle\Entity\Metalworks $metalworks
     */
    public function setMetalworks(\SpecialOperations\GameBundle\Entity\Metalworks $metalworks)
    {
        $this->metalworks = $metalworks;
    }

    /**
     * Get metalworks
     *
     * @return SpecialOperations\GameBundle\Entity\Metalworks 
     */
    public function getMetalworks()
    {
        if(!$this->metalworks){
            $this->metalworks= new Metalworks();
            $this->metalworks->setDistrict($this);
        }
        return $this->metalworks;
    }

    /**
     * Set rafinery
     *
     * @param SpecialOperations\GameBundle\Entity\Rafinery $rafinery
     */
    public function setRafinery(\SpecialOperations\GameBundle\Entity\Rafinery $rafinery)
    {
        $this->rafinery = $rafinery;
    }

    /**
     * Get rafinery
     *
     * @return SpecialOperations\GameBundle\Entity\Rafinery 
     */
    public function getRafinery()
    {
        if(!$this->rafinery){
            $this->rafinery= new Rafinery();
            $this->rafinery->setDistrict($this);
        }
        return $this->rafinery;
    }

    /**
     * Set powerPlant
     *
     * @param SpecialOperations\GameBundle\Entity\PowerPlant $powerPlant
     */
    public function setPowerPlant(\SpecialOperations\GameBundle\Entity\PowerPlant $powerPlant)
    {
        $this->powerPlant = $powerPlant;
    }

    /**
     * Get powerPlant
     *
     * @return SpecialOperations\GameBundle\Entity\PowerPlant 
     */
    public function getPowerPlant()
    {
        if(!$this->powerPlant){
            $this->powerPlant= new PowerPlant();
            $this->powerPlant->setDistrict($this);
        }
        return $this->powerPlant;
    }
    /**
     * @var SpecialOperations\GameBundle\Entity\Airport
     */
    private $airport;

    /**
     * @var SpecialOperations\GameBundle\Entity\Garnison
     */
    private $garnison;

    /**
     * @var SpecialOperations\GameBundle\Entity\Headquaters
     */
    private $headquaters;

    /**
     * @var SpecialOperations\GameBundle\Entity\DefenceStructures
     */
    private $defenceStructures;

    /**
     * @var SpecialOperations\GameBundle\Entity\Laboratory
     */
    private $laboratory;

    /**
     * @var SpecialOperations\GameBundle\Entity\Academy
     */
    private $academy;


    /**
     * Set airport
     *
     * @param SpecialOperations\GameBundle\Entity\Airport $airport
     */
    public function setAirport(\SpecialOperations\GameBundle\Entity\Airport $airport)
    {
        $this->airport = $airport;
    }

    /**
     * Get airport
     *
     * @return SpecialOperations\GameBundle\Entity\Airport 
     */
    public function getAirport()
    {
        if(!$this->airport){
            $this->airport= new Airport();
            $this->airport->setDistrict($this);
        }
        return $this->airport;
    }

    /**
     * Set garnison
     *
     * @param SpecialOperations\GameBundle\Entity\Garnison $garnison
     */
    public function setGarnison(\SpecialOperations\GameBundle\Entity\Garnison $garnison)
    {
        $this->garnison = $garnison;
    }

    /**
     * Get garnison
     *
     * @return SpecialOperations\GameBundle\Entity\Garnison 
     */
    public function getGarnison()
    {
        if(!$this->garnison){
            $this->garnison= new Garnison();
            $this->garnison->setDistrict($this);
        }
        return $this->garnison;
    }

    /**
     * Set headquaters
     *
     * @param SpecialOperations\GameBundle\Entity\Headquaters $headquaters
     */
    public function setHeadquaters(\SpecialOperations\GameBundle\Entity\Headquaters $headquaters)
    {
        $this->headquaters = $headquaters;
    }

    /**
     * Get headquaters
     *
     * @return SpecialOperations\GameBundle\Entity\Headquaters 
     */
    public function getHeadquaters()
    {
        if(!$this->headquaters){
            $this->headquaters= new Headquaters();
            $this->headquaters->setDistrict($this);
        }
        return $this->headquaters;
    }

    /**
     * Set defenceStructures
     *
     * @param SpecialOperations\GameBundle\Entity\DefenceStructures $defenceStructures
     */
    public function setDefenceStructures(\SpecialOperations\GameBundle\Entity\DefenceStructures $defenceStructures)
    {
        $this->defenceStructures = $defenceStructures;
    }

    /**
     * Get defenceStructures
     *
     * @return SpecialOperations\GameBundle\Entity\DefenceStructures 
     */
    public function getDefenceStructures()
    {
        if(!$this->defenceStructures){
            $this->defenceStructures= new DefenceStructures();
            $this->defenceStructures->setDistrict($this);
        }
        return $this->defenceStructures;
    }

    /**
     * Set laboratory
     *
     * @param SpecialOperations\GameBundle\Entity\Laboratory $laboratory
     */
    public function setLaboratory(\SpecialOperations\GameBundle\Entity\Laboratory $laboratory)
    {
        $this->laboratory = $laboratory;
    }

    /**
     * Get laboratory
     *
     * @return SpecialOperations\GameBundle\Entity\Laboratory 
     */
    public function getLaboratory()
    {
        if(!$this->laboratory){
            $this->laboratory= new Laboratory();
            $this->laboratory->setDistrict($this);
        }
        return $this->laboratory;
    }

    /**
     * Set academy
     *
     * @param SpecialOperations\GameBundle\Entity\Academy $academy
     */
    public function setAcademy(\SpecialOperations\GameBundle\Entity\Academy $academy)
    {
        $this->academy = $academy;
    }

    /**
     * Get academy
     *
     * @return SpecialOperations\GameBundle\Entity\Academy 
     */
    public function getAcademy()
    {
        if(!$this->academy){
            $this->academy= new Academy();
            $this->academy->setDistrict($this);
        }
        return $this->academy;
    }
    /**
     * @var SpecialOperations\GameBundle\Entity\Market
     */
    private $market;


    /**
     * Set market
     *
     * @param SpecialOperations\GameBundle\Entity\Market $market
     */
    public function setMarket(\SpecialOperations\GameBundle\Entity\Market $market)
    {
        $this->market = $market;
    }

    /**
     * Get market
     *
     * @return SpecialOperations\GameBundle\Entity\Market 
     */
    public function getMarket()
    {
        if(!$this->market){
            $this->market= new Market();
            $this->market->setDistrict($this);
        }
        return $this->market;
    }
    
    private function getCoalProduction(){
        return $this->getCoalMine()->getCoalProduction($this->updated->getTimestamp())*$this->getCoalBonus();
    }
    
    private function getMetalProduction(){
        return $this->getMetalworks()->getMetalProduction($this->updated->getTimestamp())*$this->getMetalBonus();
    }
    
    private function getOilProduction(){
        return $this->getRafinery()->getOilProduction($this->updated->getTimestamp())*$this->getOilBonus();
    }
    
    public function countResources(){
        $time=time()-$this->getUpdated()->getTimestamp();        
        $position=$this->getFirstInQueue();

        //if districd does not have owner yet resources are not updated
        if($this->owner){
            $this->coal+=$this->getCoalProduction();
            if($this->coal>$this->getCoalStorage()->getCapacity()){
                $this->coal=$this->getCoalStorage()->getCapacity();
            }
            $this->metal+=$this->getMetalProduction();
            if($this->metal>$this->getMetalStorage()->getCapacity()){
                $this->metal=$this->getMetalStorage()->getCapacity();
            }
            $this->oil+=$this->getOilProduction();
            if($this->oil>$this->getOilTank()->getCapacity()){
                $this->oil=$this->getOilTank()->getCapacity();
            }
            $this->population+=($this->morale+10)*$this->population*0.01*$time/District::TIME;
        }
    }
    /**
     * @var SpecialOperations\GameBundle\Entity\CoalStorage
     */
    private $coalStorage;

    /**
     * @var SpecialOperations\GameBundle\Entity\MetalStorage
     */
    private $metalStorage;

    /**
     * @var SpecialOperations\GameBundle\Entity\OilTank
     */
    private $oilTank;


    /**
     * Set coalStorage
     *
     * @param SpecialOperations\GameBundle\Entity\CoalStorage $coalStorage
     */
    public function setCoalStorage(\SpecialOperations\GameBundle\Entity\CoalStorage $coalStorage)
    {
        $this->coalStorage = $coalStorage;
    }

    /**
     * Get coalStorage
     *
     * @return SpecialOperations\GameBundle\Entity\CoalStorage 
     */
    public function getCoalStorage()
    {
        if(!$this->coalStorage){
            $this->coalStorage=new CoalStorage();
            $this->coalStorage->setDistrict($this);
        }
        return $this->coalStorage;
    }

    /**
     * Set metalStorage
     *
     * @param SpecialOperations\GameBundle\Entity\MetalStorage $metalStorage
     */
    public function setMetalStorage(\SpecialOperations\GameBundle\Entity\MetalStorage $metalStorage)
    {
        $this->metalStorage = $metalStorage;
    }

    /**
     * Get metalStorage
     *
     * @return SpecialOperations\GameBundle\Entity\MetalStorage 
     */
    public function getMetalStorage()
    {
        if(!$this->metalStorage){
            $this->metalStorage= new MetalStorage();
            $this->metalStorage->setDistrict($this);
        }
        return $this->metalStorage;
    }

    /**
     * Set oilTank
     *
     * @param SpecialOperations\GameBundle\Entity\OilTank $oilTank
     */
    public function setOilTank(\SpecialOperations\GameBundle\Entity\OilTank $oilTank)
    {
        $this->oilTank = $oilTank;
    }

    /**
     * Get oilTank
     *
     * @return SpecialOperations\GameBundle\Entity\OilTank 
     */
    public function getOilTank()
    {
        if(!$this->oilTank){
            $this->oilTank= new OilTank();
            $this->oilTank->setDistrict($this);
        }
        return $this->oilTank;
    }
    
    public function getCapacity(){
        return intval($this->getHeadquaters()->getLevel()/5)+15;
    }
    
    public function getBuildingsCount(){
        $count=0;
        foreach($this->getBuildings() as $building){
            $count+=$building->getLevel();
        }
        return $count;
    }
    /**
     * @var SpecialOperations\GameBundle\Entity\Building
     */
    private $buildings;


    /**
     * Add Buildings
     *
     * @param SpecialOperations\GameBundle\Entity\Building $buildings
     */
    public function addBuilding(\SpecialOperations\GameBundle\Entity\Building $buildings)
    {
        $this->buildings[] = $buildings;
    }

    /**
     * Get Buildings
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getBuildings()
    {
        return $this->buildings;
    }
    
    /**
     * Returns the proper building, basing at building type
     * @param string $type
     * @return Building 
     */
    public function getBuilding($type){
        switch($type){
            case Building::CoalMine:
                return $this->getCoalMine();
                break;
            case Building::Rafinery:
                return $this->getRafinery();
                break;
            case Building::OilTank:
                return $this->getOilTank();
                break;
            case Building::Metalworks:
                return $this->getRafinery();
                break;
            case Building::CoalStorage:
                return $this->getCoalStorage();
                break;
            case Building::MetalStorage:
                return $this->getMetalStorage();
                break;
            case Building::Academy:
                return $this->getAcademy();
                break;
            case Building::Airport:
                return $this->getAirport();
                break;
            case Building::DefenceStructures:
                return $this->getDefenceStructures();
                break;
            case Building::Garnison:
                return $this->getGarnison();
                break;
            case Building::Headquaters:
                return $this->getHeadquaters();
                break;
            case Building::Laboratory:
                return $this->getLaboratory();
                break;
            case Building::Market:
                return $this->getMarket();
                break;
            case Building::PowerPlant:
                return $this->getPowerPlant();
                break;
        }
    }
    
    
    public function addToQueue(Building $building, $action){
        if($this->getQueueLength()<$this->getMaxQueueLength()){
            $position = new QueuePosition();
            $position->setAction($action);
            $position->setBuilding($building);
            $position->setPlace($this->getQueueLength()+1);
            $position->setDistrict($this);

            $this->addQueuePosition($position);
        }
    }
    
    /**
     *
     * @return QueuePosition $position 
     */
    public function getFirstInQueue(){
        foreach($this->getQueuePositions() as $position){
//            $position=new QueuePosition();
            if($position->getPlace()==1){
                return $position;
            }
        }
    }
    
    /**
     * Returns current queue length
     * @return type 
     */
    public function getQueueLength(){
        return count($this->getQueuePositions());
    }
    
    public function getMaxQueueLength(){
        return 3+(int)($this->getHeadquaters()->getLevel()/5);
    } 
    
    
    /**
     * @var SpecialOperations\GameBundle\Entity\QueuePosition
     */
    private $queuePositions;


    /**
     * Add queuePositions
     *
     * @param SpecialOperations\GameBundle\Entity\QueuePosition $queuePositions
     */
    public function addQueuePosition(\SpecialOperations\GameBundle\Entity\QueuePosition $queuePositions)
    {
        $this->queuePositions[] = $queuePositions;
    }

    /**
     * Get queuePositions
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getQueuePositions()
    {
        return $this->queuePositions;
    }
}